module path_selector#(
	parameter VALUE_WIDTH = 1040,//32*12+33*8*2+128: 32 next_index(12bits)
    parameter NEXT_INDEX_WIDTH = 12,//output is one next_index we need
    parameter TIME_COUNTER_WIDTH = 16,//64 bits counter(64=8*8)
    parameter PATH_ID_WIDTH = 6,//6-bits number contaiins 0~32
    parameter PATH_COUNT = 33,
    parameter FIFO_DEPTH = 8,

    parameter WEIGHT_WIDTH = 8,
    parameter SELECT_WIDTH = WEIGHT_WIDTH//8 bits can be 0~255
)(
    input  wire                         clk,
	input  wire                         rst,   

    input  wire                         s_mat_hit,
    input  wire [VALUE_WIDTH-1:0]       s_mat_value,
    input  wire                         s_mat_valid,
    output wire                         s_mat_ready,
    
    output wire                         m_mat_hit,
    output wire [NEXT_INDEX_WIDTH-1:0]  m_mat_value,
    output wire                         m_mat_valid,
    input  wire                         m_mat_ready
);

//define interl signals which is calculated by former logic block(ALU)
reg                         s_mat_hit_reg,   s_mat_hit_dly;
reg  [VALUE_WIDTH-1:0]      s_mat_value_reg;
reg  [NEXT_INDEX_WIDTH-1:0] s_mat_value_dly;
reg                         s_mat_valid_reg, s_mat_valid_dly;

assign                      s_mat_ready = (fifo_count < 4);


//from action_data:'s_mat_value' to next_index(12):'m_mat_value_int'

//ALU logic begin
wire [SELECT_WIDTH-1:0]       path_selector;
reg  [PATH_ID_WIDTH-1:0]      path_id_reg;

wire [TIME_COUNTER_WIDTH-1:0] time_counter;
reg  [TIME_COUNTER_WIDTH-1:0] time_counter_reg;
assign                        time_counter = time_counter_reg;

//random number(path_selector) generator
//time counter
always @(posedge clk)begin
    if(rst)
        time_counter_reg <= 'd0;
    else
        time_counter_reg <= time_counter_reg + 1;
end

//hash
toep_hash #(
    .DATA_WIDTH(TIME_COUNTER_WIDTH/8),
    .INDEX_WIDTH(SELECT_WIDTH),//hash output is a 8-bits index used to select path id
    .HASH_KEY_WIDTH(TIME_COUNTER_WIDTH)
) toep_hash_inst(
    .clk(clk),
    .rst(rst),
    .hash_key_data(1234567),
    .hash_key_valid(1),
    .data(time_counter),
    .index(path_selector)//output path_selector
);
/* random number generator end */

//get weight interval bounds from s_mat_value
wire [WEIGHT_WIDTH-1:0]  weight_left[0:PATH_COUNT-1];
wire [WEIGHT_WIDTH-1:0]  weight_right[0:PATH_COUNT-1];

// valid[32]-left[32]-right[32] ... valid[0]-left[0]-right[0]
generate

    genvar i,j;

    for (i = 0; i < PATH_COUNT; i = i + 1) begin
        assign weight_right[i] = s_mat_value[(i*(2*WEIGHT_WIDTH+1)) +: WEIGHT_WIDTH];
    end

    for (j = 0; j < PATH_COUNT; j = j + 1) begin
        assign weight_left[j] = s_mat_value[(j*(2*WEIGHT_WIDTH+1)+WEIGHT_WIDTH) +: WEIGHT_WIDTH];
    end


endgenerate

integer  k;

always @(posedge clk)begin
    s_mat_valid_reg <= s_mat_valid & s_mat_ready;
    s_mat_value_reg <= s_mat_value;
    s_mat_hit_reg   <= s_mat_hit;

    s_mat_hit_dly   <= s_mat_hit_reg;
    s_mat_valid_dly <= s_mat_valid_reg;
    

    for(k = 0; k < PATH_COUNT; k = k + 1)begin
        if((path_selector > weight_left[k]) && (path_selector >= weight_right[k]))begin
            path_id_reg <= k;
        end
    end

    s_mat_value_dly <= s_mat_value_reg[(PATH_COUNT*2*(WEIGHT_WIDTH+1) + path_id_reg*NEXT_INDEX_WIDTH) +: NEXT_INDEX_WIDTH];

    if(rst)begin
        path_id_reg <= 0;
    end
end

//ALU logic end

//handle backpressure logic through axis_srl_fifo module
wire [$clog2(FIFO_DEPTH+1)-1:0] fifo_count;
axis_srl_fifo #(
    .DATA_WIDTH(NEXT_INDEX_WIDTH+1),
    .KEEP_ENABLE(0),
    .LAST_ENABLE(0),
    .ID_ENABLE(0),
    .DEST_ENABLE(0),
    .USER_ENABLE(0),
    .DEPTH(FIFO_DEPTH)
) ofib1_phv_fifo_inst (
    .clk(clk),
    .rst(rst),

    /*
     * AXI input
     */
    .s_axis_tdata({s_mat_hit_dly, s_mat_value_dly}),
    .s_axis_tkeep(0),
    .s_axis_tvalid(s_mat_valid_dly),
    .s_axis_tready(),
    .s_axis_tlast(1'b0),
    .s_axis_tid(8'b0),
    .s_axis_tdest(8'b0),
    .s_axis_tuser(1'b0),

    /*
     * AXI output
     */
    .m_axis_tdata({m_mat_hit,m_mat_value}),
    .m_axis_tkeep(),
    .m_axis_tvalid(m_mat_valid),
    .m_axis_tready(m_mat_ready),
    .m_axis_tlast(),
    .m_axis_tid(),
    .m_axis_tdest(),
    .m_axis_tuser(),

    /*
     * Status
     */
    .count(fifo_count)
);

endmodule